package	com.jyx.reflect.test;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;

import com.jyx.reflect.bean.IComputer;

public class Reflection	{
	
	public double x;
	public Double y;
	public Reflection(double x, Double y){
		
	}
	public Reflection(){}
	public static void main(String args[]) throws Exception	{

		Reflection ref = new Reflection();
		// 获取构造方法的权限修饰符
		/*System.out.println(Modifier.toString(ref.getClass().getConstructors()[0].getModifiers()));
		Constructor<?>[]  pars = ref.getClass().getConstructors();
		for (Constructor<?> p : pars) {
			for (Class<?> c : p.getParameterTypes()) {
				System.out.println(c.getName());
			}
			System.out.println(p.getName());
		}*/
		
		// 浅析类加载器
		MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
		Subject sub = (Subject) myInvocationHandler.bind(new RealSubject());
		System.out.println(sub.say("hello", 12));
		
		// 获取 Class的属性
		/*ref.getConstructor();*/
		
		// 复制对象
		/*Customer customer = new Customer("Tom", 21);
		customer.setId(new Long(1));
		
		Customer customerCopy = (Customer) ref.copy(customer);
		System.out.println("Copy information:" + 
				customerCopy.getId() + " " + 
				customerCopy.getName() + " " + 
				customerCopy.getAge());*/

		// 用反射机制调用对象的方法 
		/*ref.invokeTester();*/
		
		// 修改对象的属性value
		/*ref.updateField(ref);*/
	}

	/**
	 * 获取Class的属性
	 * @throws Exception
	 */
	@SuppressWarnings({"unchecked", "rawtypes"})
	public void	getConstructor() throws	Exception {
		Class c = Class.forName("java.lang.Long");
		Class cs[] = {java.lang.String.class};
		
		System.out.println("\n-------------------------------\n");

		System.out.println("1、通过参数获取指定Class对象的构造方法：");
		Constructor	cst1 = c.getConstructor(cs);
		System.out.println(cst1.toString());

		System.out.println("2、通过参数获取指定Class对象所表示的类或接口的构造方法：");
		Constructor cst2 =	c.getDeclaredConstructor(cs);
		System.out.println(cst2.toString());

		System.out.println("3、获取本地或匿名类Constructor 对象，它表示基础类的立即封闭构造方法。");
		Constructor cst3	= c.getEnclosingConstructor();
		if (cst3 != null) 
			System.out.println(cst3.toString());
		else 
			System.out.println("-- 没有获取到任何构造方法！");

		System.out.println("4、获取指定Class对象的所有构造方法：");
		Constructor[] csts =	c.getConstructors();
		for (int	i =	0; i < csts.length;	i++) {
			System.out.println(csts[i].toString());
		}

		System.out.println("\n-------------------------------\n");

		System.out.println("1、返回直接实现的接口：");
		Type	types1[] = c.getGenericInterfaces();
		for (int	i =	0; i < types1.length; i++) {
			System.out.println(types1[i].toString());
		}

		System.out.println("2、返回直接超类：");
		Type	type1 =	c.getGenericSuperclass();
		System.out.println(type1.toString());

		System.out.println("3、返回超类和所有实现的接口：");
		Class[] cis = c.getClasses();
		for (int	i =	0; i < cis.length; i++)	{
			System.out.println(cis[i].toString());
		}

		System.out.println("4、实现的接口");
		Class cs1[] = c.getInterfaces();
		for (int	i =	0; i < cs1.length; i++)	{
			System.out.println(cs1[i].toString());
		}

		System.out.println("\n-------------------------------\n");

		System.out.println("1、类或接口的所有可访问公共字段：");
		Field fs1[] = c.getFields();
		for (int	i =	0; i < fs1.length; i++)	{
			System.out.println(fs1[i].toString());
		}

		System.out.println("2、类或接口的指定已声明指定公共成员字段：");
		Field f1	= c.getField("MIN_VALUE");
		System.out.println(f1.toString());

		System.out.println("3、类或接口所声明的所有字段：");
		Field fs2[] = c.getDeclaredFields();
		for (int	i =	0; i < fs2.length; i++)	{
			System.out.println(fs2[i].toString());
		}

		System.out.println("4、类或接口的指定已声明指定字段：");
		Field f2	= c.getDeclaredField("serialVersionUID");
		System.out.println(f2.toString());

		System.out.println("\n-------------------------------\n");

		System.out.println("1、返回类所有的公共成员方法：");
		Method m1[] = c.getMethods();
		System.out.println(m1.length);
		for	(int i = 0;	i <	m1.length; i++)	{
			System.out.println(m1[i].toString());
		}
		System.out.println("2、返回指定公共成员方法：");
		Method m2 =	c.getMethod("longValue", new Class[]{});
		System.out.println(m2.toString());

	}
	
	/**
	 * RefltTester(反射仪)复制对象的方法
	 * @param object
	 * @return
	 * @throws Exception
	 */
	public Object copy(Object object) throws Exception {
        // 获得对象的类型
        Class<?> classType = object.getClass();
        System.out.println("Class:" + classType.getName());
 
        // 通过默认构造方法创建一个新的对象
        Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
 
        // 获得对象的所有属性
        Field fields[] = classType.getDeclaredFields();
 
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
 
            String fieldName = field.getName();
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            // 获得和属性对应的getXXX()方法的名字
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            // 获得和属性对应的setXXX()方法的名字
            String setMethodName = "set" + firstLetter + fieldName.substring(1);
 
            // 获得和属性对应的getXXX()方法
            Method getMethod = classType.getMethod(getMethodName, new Class[]{});
            // 获得和属性对应的setXXX()方法
            Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});
 
            // 调用原对象的getXXX()方法
            Object value = getMethod.invoke(object, new Object[]{});
            System.out.println(fieldName + ":" + value);
            // 调用拷贝对象的setXXX()方法
            setMethod.invoke(objectCopy, new Object[]{value});
        }
        return objectCopy;
    }
	
	/**
	 * 用反射机制调用对象的方法 
	 */
	public void invokeTester() throws Exception{
		Class<?> classType = Reflection.class;
		Object invokeTester = classType.newInstance();

		// Object invokeTester = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});


		//获取InvokeTester类的add()方法
		Method addMethod = classType.getMethod("add", new Class[]{int.class, int.class});
		//调用invokeTester对象上的add()方法
		Object result = addMethod.invoke(invokeTester, new Object[]{new Integer(100), new Integer(200)});
		System.out.println((Integer) result);


		//获取InvokeTester类的echo()方法
		Method echoMethod = classType.getMethod("echo", new Class[]{String.class});
		//调用invokeTester对象的echo()方法
		result = echoMethod.invoke(invokeTester, new Object[]{"Hello"});
		System.out.println((String) result);
	}
	
    public int add(int param1, int param2) {
        return param1 + param2;
    }
 
    public String echo(String msg) {
        return "echo: " + msg;
    }
	
	/**
	 * 修改对象属性的value
	 * @param ref 对象
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public void updateField(Reflection ref) throws Exception{
		
		Class clazz = Class.forName(ref.getClass().getName());
		// Class c = Reflection.class;
		Field xf = clazz.getField("x");
		Field yf = clazz.getField("y");
		System.out.println("befor:\nxf\t"+xf.get(ref)+"\nty\t"+yf.get(ref));
		xf.set(ref, 1.1d);
		yf.set(ref, 1.2);
		
		System.out.println("after:\nxf\t"+xf.get(ref)+"\nyf\t"+yf.get(ref));
	}
	 
}

@SuppressWarnings("serial")
class Selecter extends JFrame {

	JTextArea area;
	
	private void initFrame() {
		
		this.setName("电脑信息查询");
		this.setLayout(new FlowLayout());
		this.setSize(new Dimension(340, 400));
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(3);
		JLabel lable = new JLabel("查询的电脑：");
		final JTextField text = new JTextField(13);
		JButton button1 = new JButton("查询");
		JButton button2 = new JButton("测试");
		area = new JTextArea();
		JScrollPane scrollpane = new JScrollPane(area);
		scrollpane.setPreferredSize(new Dimension(290, 290));
		this.add(lable);
		this.add(text);
		this.add(button1);
		this.add(button2);
		this.add(scrollpane);
		this.setVisible(true);// 设置窗体可见

		// 给按钮1添加监听器
		button1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String text1 = text.getText();
				getDescription(text1);
			}
		});
		// 给按钮2添加监听器
		button2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String text2 = text.getText();
				IComputer com = (IComputer) getComputer(text2);
				testComputer(com, "startScreen");
			}
		});

	}

	// 得到所查询电脑的详细信息
	public void getDescription(String type) {
		try {
			System.out.println(type);
			Class cla = Class.forName(type);
			// 生成一个实例对象，在编译时我们并不知道obj是什么类型
			Object obj = cla.newInstance();
			// 获得type类型所有已定义类变量及方法。
			Field[] fileds = cla.getDeclaredFields();
			area.append(cla.getSimpleName()+"电脑的详细信息是：\n");

			for (int i = 0; i < fileds.length; i++) {
				fileds[i].setAccessible(true);
				// 输出类变量的定义及obj实例中对应的值
				area.append(fileds[i].getName() + ":" + fileds[i].get(obj) + "\n");
			}
			area.append("\n");
		} catch (Exception e) {
			area.append("对不起,没有这种电脑的信息！\n\n");
		}
	}

	// 使用电脑的某个功能
	public void testComputer(Object obj, String function) {
		try {
			Class cla = obj.getClass();
			// 获得cla类中定义的无参方法。
			Method m = cla.getMethod(function, null);
			// 调用obj中名为function的无参方法。
			String aa= (String)m.invoke(obj, null);
			area.append(aa+"\n\n");
		} catch (Exception e) {}
	}

	// 拿电脑给顾客
	public Object getComputer(String type) {
		try {
			Class cla = Class.forName(type);
			Object obj = cla.newInstance();
			return obj;
		} catch (Exception e) {
			area.append("对不起,没有这种电脑的信息！\n\n");
			return null;
		}
	}

	public static void main(String[] args) {

		/*************** 以下几句是优化窗体界面的方法 ***************************/
		JFrame.setDefaultLookAndFeelDecorated(true); // 加上此语句连同窗体外框也改变
		JDialog.setDefaultLookAndFeelDecorated(true); // 加上此语句会使弹出的对话框也改变
		try {
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		} catch (Exception e) {
			e.printStackTrace();
		}
		/*************** 以上几句是优化窗体界面的方法 ***************************/

		Selecter selecter = new Selecter();
		selecter.initFrame();

	}

}
